package com.school.sports.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.school.sports.entity.ExceptionRecord;
import com.school.sports.mapper.ExceptionRecordMapper;
import com.school.sports.service.ExceptionHandlingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 异常处理服务实现类
 */
@Slf4j
@Service
public class ExceptionHandlingServiceImpl extends ServiceImpl<ExceptionRecordMapper, ExceptionRecord> implements ExceptionHandlingService {

    @Override
    public boolean recordException(Exception exception, HttpServletRequest request, Long operatorId, String operatorName) {
        try {
            ExceptionRecord record = new ExceptionRecord();

            // 基本信息
            record.setExceptionType(exception.getClass().getSimpleName());
            record.setExceptionDesc(exception.getMessage());
            record.setOccurTime(LocalDateTime.now());
            record.setExceptionLevel(determineExceptionLevel(exception, exception.getClass().getSimpleName()));

            // 堆栈信息
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            exception.printStackTrace(pw);
            record.setStackTrace(sw.toString());

            // 请求信息
            if (request != null) {
                record.setOccurLocation(request.getRequestURI());
                record.setRequestUrl(request.getRequestURL().toString());
                record.setRequestMethod(request.getMethod());
                record.setUserIp(getClientIpAddress(request));
                record.setUserAgent(request.getHeader("User-Agent"));

                // 请求参数
                Map<String, String[]> parameterMap = request.getParameterMap();
                if (!parameterMap.isEmpty()) {
                    StringBuilder params = new StringBuilder();
                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                        if (params.length() > 0) {
                            params.append(", ");
                        }
                        params.append(entry.getKey()).append("=").append(Arrays.toString(entry.getValue()));
                    }
                    record.setRequestParams(params.toString());
                }
            }

            // 操作人信息
            record.setOperatorId(operatorId);
            record.setOperatorName(operatorName);
            record.setHandleStatus(ExceptionRecord.Status.PENDING.getCode());
            record.setCreatedAt(LocalDateTime.now());
            record.setUpdatedAt(LocalDateTime.now());

            return save(record);
        } catch (Exception e) {
            log.error("记录异常信息失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean recordException(String exceptionType, String exceptionDesc, String occurLocation,
                                 Integer exceptionLevel, String stackTrace, HttpServletRequest request,
                                 Long operatorId, String operatorName) {
        try {
            ExceptionRecord record = new ExceptionRecord();

            // 基本信息
            record.setExceptionType(exceptionType);
            record.setExceptionDesc(exceptionDesc);
            record.setOccurTime(LocalDateTime.now());
            record.setOccurLocation(occurLocation);
            record.setExceptionLevel(exceptionLevel != null ? exceptionLevel : ExceptionRecord.Level.MEDIUM.getCode());
            record.setStackTrace(stackTrace);

            // 请求信息
            if (request != null) {
                record.setRequestUrl(request.getRequestURL().toString());
                record.setRequestMethod(request.getMethod());
                record.setUserIp(getClientIpAddress(request));
                record.setUserAgent(request.getHeader("User-Agent"));
            }

            // 操作人信息
            record.setOperatorId(operatorId);
            record.setOperatorName(operatorName);
            record.setHandleStatus(ExceptionRecord.Status.PENDING.getCode());
            record.setCreatedAt(LocalDateTime.now());
            record.setUpdatedAt(LocalDateTime.now());

            return save(record);
        } catch (Exception e) {
            log.error("记录异常信息失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public IPage<ExceptionRecord> getExceptionRecordPage(Integer currentPage, Integer pageSize, ExceptionRecord exceptionRecord) {
        Page<ExceptionRecord> page = new Page<>(currentPage, pageSize);
        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();

        // 构建查询条件
        if (exceptionRecord != null) {
            if (StringUtils.hasText(exceptionRecord.getExceptionType())) {
                queryWrapper.like("exception_type", exceptionRecord.getExceptionType());
            }
            if (StringUtils.hasText(exceptionRecord.getExceptionDesc())) {
                queryWrapper.like("exception_desc", exceptionRecord.getExceptionDesc());
            }
            if (StringUtils.hasText(exceptionRecord.getOccurLocation())) {
                queryWrapper.like("occur_location", exceptionRecord.getOccurLocation());
            }
            if (exceptionRecord.getExceptionLevel() != null) {
                queryWrapper.eq("exception_level", exceptionRecord.getExceptionLevel());
            }
            if (exceptionRecord.getHandleStatus() != null) {
                queryWrapper.eq("handle_status", exceptionRecord.getHandleStatus());
            }
            if (exceptionRecord.getOccurTime() != null) {
                queryWrapper.ge("occur_time", exceptionRecord.getOccurTime());
            }
        }

        // 按发生时间倒序排列
        queryWrapper.orderByDesc("occur_time");

        return page(page, queryWrapper);
    }

    @Override
    public ExceptionRecord getExceptionRecordById(Long recordId) {
        return getById(recordId);
    }

    @Override
    public boolean handleExceptionRecord(Long recordId, Long handlerId, String handlerName, String solution) {
        try {
            ExceptionRecord record = getById(recordId);
            if (record == null) {
                return false;
            }

            record.setHandleStatus(ExceptionRecord.Status.RESOLVED.getCode());
            record.setHandlerId(handlerId);
            record.setHandlerName(handlerName);
            record.setSolution(solution);
            record.setHandleTime(LocalDateTime.now());
            record.setUpdatedAt(LocalDateTime.now());

            return updateById(record);
        } catch (Exception e) {
            log.error("处理异常记录失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean batchHandleExceptionRecords(List<Long> recordIds, Long handlerId, String handlerName, String solution) {
        try {
            List<ExceptionRecord> records = listByIds(recordIds);
            for (ExceptionRecord record : records) {
                record.setHandleStatus(ExceptionRecord.Status.RESOLVED.getCode());
                record.setHandlerId(handlerId);
                record.setHandlerName(handlerName);
                record.setSolution(solution);
                record.setHandleTime(LocalDateTime.now());
                record.setUpdatedAt(LocalDateTime.now());
            }

            return updateBatchById(records);
        } catch (Exception e) {
            log.error("批量处理异常记录失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean ignoreExceptionRecord(Long recordId, Long handlerId, String handlerName, String reason) {
        try {
            ExceptionRecord record = getById(recordId);
            if (record == null) {
                return false;
            }

            record.setHandleStatus(ExceptionRecord.Status.IGNORED.getCode());
            record.setHandlerId(handlerId);
            record.setHandlerName(handlerName);
            record.setSolution("忽略原因：" + reason);
            record.setHandleTime(LocalDateTime.now());
            record.setUpdatedAt(LocalDateTime.now());

            return updateById(record);
        } catch (Exception e) {
            log.error("忽略异常记录失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean batchIgnoreExceptionRecords(List<Long> recordIds, Long handlerId, String handlerName, String reason) {
        try {
            List<ExceptionRecord> records = listByIds(recordIds);
            for (ExceptionRecord record : records) {
                record.setHandleStatus(ExceptionRecord.Status.IGNORED.getCode());
                record.setHandlerId(handlerId);
                record.setHandlerName(handlerName);
                record.setSolution("忽略原因：" + reason);
                record.setHandleTime(LocalDateTime.now());
                record.setUpdatedAt(LocalDateTime.now());
            }

            return updateBatchById(records);
        } catch (Exception e) {
            log.error("批量忽略异常记录失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public Map<String, Object> getExceptionStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        Map<String, Object> statistics = new HashMap<>();

        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();
        if (startTime != null) {
            queryWrapper.ge("occur_time", startTime);
        }
        if (endTime != null) {
            queryWrapper.le("occur_time", endTime);
        }

        // 总数
        statistics.put("totalCount", count(queryWrapper));

        // 按状态统计
        Map<String, Long> statusCount = new HashMap<>();
        for (ExceptionRecord.Status status : ExceptionRecord.Status.values()) {
            QueryWrapper<ExceptionRecord> statusQuery = new QueryWrapper<>();
            if (startTime != null) {
                statusQuery.ge("occur_time", startTime);
            }
            if (endTime != null) {
                statusQuery.le("occur_time", endTime);
            }
            statusQuery.eq("handle_status", status.getCode());
            statusCount.put(status.getDesc(), count(statusQuery));
        }
        statistics.put("statusCount", statusCount);

        // 按级别统计
        Map<String, Long> levelCount = new HashMap<>();
        for (ExceptionRecord.Level level : ExceptionRecord.Level.values()) {
            QueryWrapper<ExceptionRecord> levelQuery = new QueryWrapper<>();
            if (startTime != null) {
                levelQuery.ge("occur_time", startTime);
            }
            if (endTime != null) {
                levelQuery.le("occur_time", endTime);
            }
            levelQuery.eq("exception_level", level.getCode());
            levelCount.put(level.getDesc(), count(levelQuery));
        }
        statistics.put("levelCount", levelCount);

        return statistics;
    }

    @Override
    public List<Map<String, Object>> getExceptionStatisticsByType(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getExceptionStatisticsByType(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getExceptionStatisticsByLevel(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getExceptionStatisticsByLevel(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getExceptionStatisticsByLocation(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getExceptionStatisticsByLocation(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getExceptionStatisticsByStatus(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.getExceptionStatisticsByStatus(startTime, endTime);
    }

    @Override
    public List<Map<String, Object>> getExceptionTrendData(LocalDateTime startTime, LocalDateTime endTime, String interval) {
        return baseMapper.getExceptionTrendData(startTime, endTime, interval);
    }

    @Override
    public Map<String, Object> generateExceptionReport(LocalDateTime startTime, LocalDateTime endTime, String reportType) {
        Map<String, Object> report = new HashMap<>();

        // 报告基本信息
        report.put("reportType", reportType);
        report.put("startTime", startTime);
        report.put("endTime", endTime);
        report.put("generateTime", LocalDateTime.now());

        // 统计数据
        report.put("statistics", getExceptionStatistics(startTime, endTime));
        report.put("typeStatistics", getExceptionStatisticsByType(startTime, endTime));
        report.put("levelStatistics", getExceptionStatisticsByLevel(startTime, endTime));
        report.put("locationStatistics", getExceptionStatisticsByLocation(startTime, endTime));
        report.put("statusStatistics", getExceptionStatisticsByStatus(startTime, endTime));
        report.put("trendData", getExceptionTrendData(startTime, endTime, "day"));

        // 严重异常列表
        QueryWrapper<ExceptionRecord> severeQuery = new QueryWrapper<>();
        severeQuery.eq("exception_level", ExceptionRecord.Level.SEVERE.getCode());
        if (startTime != null) {
            severeQuery.ge("occur_time", startTime);
        }
        if (endTime != null) {
            severeQuery.le("occur_time", endTime);
        }
        severeQuery.orderByDesc("occur_time");
        severeQuery.last("LIMIT 10");
        report.put("severeExceptions", list(severeQuery));

        // 待处理异常列表
        QueryWrapper<ExceptionRecord> pendingQuery = new QueryWrapper<>();
        pendingQuery.eq("handle_status", ExceptionRecord.Status.PENDING.getCode());
        if (startTime != null) {
            pendingQuery.ge("occur_time", startTime);
        }
        if (endTime != null) {
            pendingQuery.le("occur_time", endTime);
        }
        pendingQuery.orderByDesc("occur_time");
        pendingQuery.last("LIMIT 10");
        report.put("pendingExceptions", list(pendingQuery));

        return report;
    }

    @Override
    public long getPendingExceptionCount() {
        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("handle_status", ExceptionRecord.Status.PENDING.getCode());
        return count(queryWrapper);
    }

    @Override
    public long getSevereExceptionCount() {
        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("exception_level", ExceptionRecord.Level.SEVERE.getCode());
        return count(queryWrapper);
    }

    @Override
    public List<ExceptionRecord> getRecentExceptions(Integer limit) {
        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("occur_time");
        if (limit != null && limit > 0) {
            queryWrapper.last("LIMIT " + limit);
        }
        return list(queryWrapper);
    }

    @Override
    public boolean deleteExceptionRecord(Long recordId) {
        return removeById(recordId);
    }

    @Override
    public boolean batchDeleteExceptionRecords(List<Long> recordIds) {
        return removeByIds(recordIds);
    }

    @Override
    public int cleanExpiredExceptionRecords(LocalDateTime beforeTime) {
        QueryWrapper<ExceptionRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("occur_time", beforeTime);
        queryWrapper.eq("handle_status", ExceptionRecord.Status.RESOLVED.getCode());
        return baseMapper.delete(queryWrapper);
    }

    @Override
    public Integer determineExceptionLevel(Exception exception, String exceptionType) {
        // 根据异常类型和消息判定异常级别
        if (exception == null) {
            return ExceptionRecord.Level.MEDIUM.getCode();
        }

        String message = exception.getMessage();
        String className = exception.getClass().getSimpleName();

        // 严重异常
        if (isSevereException(className, message)) {
            return ExceptionRecord.Level.SEVERE.getCode();
        }

        // 轻微异常
        if (isSlightException(className, message)) {
            return ExceptionRecord.Level.SLIGHT.getCode();
        }

        // 默认中等异常
        return ExceptionRecord.Level.MEDIUM.getCode();
    }

    @Override
    public String getExceptionHandlingSuggestion(String exceptionType, String exceptionDesc) {
        // 根据异常类型提供处理建议
        if (!StringUtils.hasText(exceptionType)) {
            return "请检查异常详细信息，联系系统管理员处理";
        }

        switch (exceptionType) {
            case "BusinessException":
                return "业务逻辑异常，请检查业务规则和数据有效性";
            case "SQLIntegrityConstraintViolationException":
                return "数据库约束冲突，请检查数据完整性";
            case "MethodArgumentNotValidException":
            case "BindException":
            case "ConstraintViolationException":
                return "参数校验失败，请检查请求参数格式和有效性";
            case "AuthenticationException":
                return "认证失败，请检查用户身份信息";
            case "AccessDeniedException":
                return "权限不足，请联系管理员分配相应权限";
            case "SQLException":
                return "数据库操作异常，请检查数据库连接和SQL语句";
            case "IOException":
                return "文件操作异常，请检查文件路径和权限";
            case "NumberFormatException":
            case "IllegalArgumentException":
                return "参数格式错误，请检查参数类型和格式";
            default:
                return "系统异常，请联系技术支持处理";
        }
    }

    /**
     * 判断是否为严重异常
     */
    private boolean isSevereException(String className, String message) {
        if (!StringUtils.hasText(className)) {
            return false;
        }

        // 数据库相关异常
        if (className.contains("SQL") || className.contains("Database")) {
            return true;
        }

        // 内存相关异常
        if (className.contains("OutOfMemoryError") || className.contains("StackOverflowError")) {
            return true;
        }

        // 安全相关异常
        if (className.contains("Security") || className.contains("AccessDenied")) {
            return true;
        }

        // 根据异常消息判断
        if (StringUtils.hasText(message)) {
            String lowerMessage = message.toLowerCase();
            if (lowerMessage.contains("connection") || lowerMessage.contains("timeout") ||
                lowerMessage.contains("fatal") || lowerMessage.contains("critical")) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断是否为轻微异常
     */
    private boolean isSlightException(String className, String message) {
        if (!StringUtils.hasText(className)) {
            return false;
        }

        // 参数校验异常
        if (className.contains("Validation") || className.contains("Argument")) {
            return true;
        }

        // 业务逻辑异常
        if (className.contains("Business")) {
            return true;
        }

        // 根据异常消息判断
        if (StringUtils.hasText(message)) {
            String lowerMessage = message.toLowerCase();
            if (lowerMessage.contains("not found") || lowerMessage.contains("invalid") ||
                lowerMessage.contains("empty")) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}